#include "mypaint.h"
#include <QDebug>

using namespace std;
vector<string> split(const string& str, const string& delim) {
  vector<string> res;
  if ("" == str) return res;
  //先将要切割的字符串从string类型转换为char*类型  
  char * strs = new char[str.length() + 1]; //不要忘了  
  strcpy(strs, str.c_str());

  char * d = new char[delim.length() + 1];
  strcpy(d, delim.c_str());

  char *p = strtok(strs, d);
  while (p) {
    string s = p; //分割得到的字符串转换为string类型  
    res.push_back(s); //存入结果数组  
    p = strtok(NULL, d);
  }

  return res;
}

#define GET_VNAME(Variable) (#Variable)

MyPaint::MyPaint(QWidget *parent) :
QMainWindow(parent)
{
  _lpress = false;//初始鼠标左键未按下
  _drawType = 0;//初始为什么都不画
  _drag = 0;//默认非拖拽模式
  _begin = pos();//拖拽的参考坐标，方便计算位移
  _openflag = 0;//初始不打开图片
  //设置窗体大小、位置
  rectWidgt.setRect(0, 30, 600, 400 - 30);
  this->setGeometry(rectWidgt.x() + 350, rectWidgt.y() + 200 - 30, rectWidgt.width(), rectWidgt.height() + 30);
  //resize(600, 400); //设置窗口初始大小
  int side = qMin(width(), height()); //创建窗口宽高参数
  setMouseTracking(true);//开启鼠标实时追踪，监听鼠标移动事件，默认只有按下时才监听
  //设置背景黑色
  //方法一
  QPalette palt(this->palette());
  palt.setColor(QPalette::Background, Qt::white);
  this->setAutoFillBackground(true);
  this->setPalette(palt);
  //方法二
  //this->setStyleSheet("background-color:red;");

  //创建工具栏
  QToolBar *tbar = addToolBar(tr("Tool"));
  tbar->setMovable(false);//工具栏不可移动
  tbar->setIconSize(QSize(16, 16));//设置动作图标的尺寸
  tbar->setStyleSheet("background-color:rgb(199,237,204)");//背景色

  _Rmenu = new QMenu(this);//创建右键菜单
  _Rmenu->addAction(tr("Save  \tCtrl+S"), this, SLOT(SavePic()));//添加菜单动作
  _Rmenu->addAction(tr("Exit  \tALT+F4"), this, SLOT(close()));//添加菜单动作
  _Rmenu->addAction(tr("Done  \tALT+F5"), this, SLOT(lineDone()));//添加菜单动作
  _Rmenu->setStyleSheet("background-color:rgb(199,237,204)");//设置背景色

  QAction *openAction = new QAction(tr("&Open"), this);//打开动作
  openAction->setIcon(QIcon(":/png/images/open.png"));//图标
  openAction->setShortcut(QKeySequence(tr("Ctrl+O")));//热键
  tbar->addAction(openAction);//添加到工具栏

  QAction *saveAction = new QAction(tr("&Save"), this);//保存动作
  saveAction->setIcon(QIcon(":/png/images/save.png"));//图标
  saveAction->setShortcut(QKeySequence(tr("Ctrl+S")));//热键
  tbar->addAction(saveAction);//添加到工具栏

  QAction *saveasAction = new QAction(tr("&Save As"), this);//保存动作
  saveasAction->setIcon(QIcon(":/png/images/saveas.png"));//图标
  saveasAction->setShortcut(QKeySequence(tr("Ctrl+ALT+S")));//热键
  tbar->addAction(saveasAction);//添加到工具栏

  QAction *lineAction = new QAction(tr("&Line"), this);//直线动作
  lineAction->setIcon(QIcon(":/png/images/line.png"));//图标
  lineAction->setShortcut(QKeySequence(tr("Ctrl+L")));//热键
  tbar->addAction(lineAction);//添加到工具栏

  QAction *linesAction = new QAction(tr("&铅笔"), this);//铅笔动作
  linesAction->setIcon(QIcon(":/png/images/lines.png"));//图标
  linesAction->setShortcut(QKeySequence(tr("Ctrl+P")));//热键
  tbar->addAction(linesAction);//添加到工具栏

  QAction *rectAction = new QAction(tr("&矩形"), this);//矩形动作
  rectAction->setIcon(QIcon(":/png/images/rect.png"));//图标
  rectAction->setShortcut(QKeySequence(tr("Ctrl+R")));//热键
  tbar->addAction(rectAction);

  QAction *ellipseAction = new QAction(tr("&椭圆"), this);//椭圆动作
  ellipseAction->setIcon(QIcon(":/png/images/ellipse.png"));//图标
  ellipseAction->setShortcut(QKeySequence(tr("Ctrl+E")));//热键
  tbar->addAction(ellipseAction);


  //连接信号与槽函数
  connect(linesAction, SIGNAL(triggered()), this, SLOT(Lines()));
  connect(rectAction, SIGNAL(triggered()), this, SLOT(Rects()));
  connect(ellipseAction, SIGNAL(triggered()), this, SLOT(Ellipses()));
  connect(lineAction, SIGNAL(triggered()), this, SLOT(Line()));
  connect(saveAction, SIGNAL(triggered()), this, SLOT(SavePic()));
  connect(openAction, SIGNAL(triggered()), this, SLOT(OpenPic()));

  //重新绘制上次的直线
  //rePaintLine();
  importData();
  update();
}

void MyPaint::paintEvent(QPaintEvent *)
{
  if (_openflag == 0)//不是打开图片的，每一次新建一个空白的画布
  {
    _pixmap = QPixmap(size());//新建pixmap
    _pixmap.fill(Qt::gray);//背景色填充为白色
  }
  QPixmap pix = _pixmap;//以_pixmap作为画布
  QPainter p(&pix);//将_pixmap作为画布

  //p.translate(300, 200); //坐标系统平移变换,把原点平移到窗口中心

  unsigned int i1 = 0, i2 = 0, i3 = 0, i4 = 0;//各种图形的索引

  for (int c = 0; c < _shape.size(); ++c)//控制用户当前所绘图形总数
  {
    if (_shape.at(c) == 1)//线条
    {
      const QVector<QPoint>& line = _lines.at(i1++);//取出一条线条
      for (int j = 0; j < line.size() - 1; ++j)//将线条的所有线段描绘出
      {
        p.drawLine(line.at(j), line.at(j + 1));
      }
    }
    else if (_shape.at(c) == 2)//矩形
    {
      p.drawRect(_rects.at(i2++));
    }
    else if (_shape.at(c) == 3)//椭圆
    {
      p.drawEllipse(_ellipse.at(i3++));
    }
    else if (_shape.at(c) == 4)//直线
    {
      p.setPen(Qt::green);
      p.drawLine(_line.at(i4).topLeft(), _line.at(i4).bottomRight());
      i4++;
    }
  }
  p.end();
  p.begin(this);//将当前窗体作为画布
  p.drawPixmap(0, 0, pix);//将pixmap画到窗体
}
void MyPaint::rePaintLine(void)
{
  //rectWidgt  窗体位置信息，限定框距离边框间隔5pix
  int pix = 5;
  QRect rect[4];//顺时针旋转 上 右 下 左
  rect[0].setTopLeft(QPoint(rectWidgt.x() + pix, rectWidgt.y() + pix));
  rect[0].setBottomRight(QPoint(rectWidgt.x() + pix + rectWidgt.width() - 2 * pix, rectWidgt.y() + pix));

  rect[1].setTopLeft(rect[0].bottomRight());
  rect[1].setBottomRight(QPoint(rectWidgt.x() + pix + rectWidgt.width() - 2 * pix, rectWidgt.y() + rectWidgt.height() - 2 * pix));

  rect[2].setTopLeft(rect[1].bottomRight());
  rect[2].setBottomRight(QPoint(rectWidgt.x() + pix, rectWidgt.y() + rectWidgt.height() - 2 * pix));

  rect[3].setTopLeft(rect[2].bottomRight());
  rect[3].setBottomRight(QPoint(rectWidgt.x() + pix, rectWidgt.y() + pix));

  for (int i = 0; i < 4; i++)
  {
    _line.append(rect[i]);//将新直线添加到直线集合
    _shape.append(4);
  }

  rect[3].setTopLeft(QPoint(200, 200));
  rect[3].setBottomRight(QPoint(300, 200));
  _line.append(rect[3]);//将新直线添加到直线集合
  _shape.append(4);

  rect[3].setRect(175, 200, 50, 50);
  _ellipse.append(rect[3]);
  _shape.append(3);
  update();
}
void MyPaint::mousePressEvent(QMouseEvent *e)
{
  if (e->button() == Qt::LeftButton)//当鼠标左键按下
  {
    if (_drawType == 1)//线条(铅笔)
    {
      _lpress = true;//左键按下标志
      QVector<QPoint> line;//鼠标按下，新的线条开始
      _lines.append(line);//将新线条添加到线条集合
      QVector<QPoint>& lastLine = _lines.last();//拿到新线条
      lastLine.append(e->pos());//记录鼠标的坐标(新线条的开始坐标)
      _shape.append(1);
    }
    else if (_drawType == 2)//矩形
    {
      _lpress = true;//左键按下标志
      if (!_drag)//非拖拽模式
      {
        QRect rect;//鼠标按下，矩形开始
        _rects.append(rect);//将新矩形添加到矩形集合
        QRect& lastRect = _rects.last();//拿到新矩形
        lastRect.setTopLeft(e->pos());//记录鼠标的坐标(新矩形的左上角坐标)
        _shape.append(2);
      }
      else if (_rects.last().contains(e->pos()))//拖拽模式、如果在矩形内按下
      {
        _begin = e->pos();//记录拖拽开始的坐标位置,方便计算位移

      }

    }
    else if (_drawType == 3)//椭圆
    {
      _lpress = true;//左键按下标志
      if (!_drag)//非拖拽模式
      {
        QRect rect;//鼠标按下，椭圆开始
        _ellipse.append(rect);//将新椭圆添加到椭圆集合
        QRect& lastEllipse = _ellipse.last();//拿到新椭圆
        lastEllipse.setTopLeft(e->pos());//记录鼠标的坐标(新椭圆的左上角坐标)
        _shape.append(3);
      }
      else if (_ellipse.last().contains(e->pos()))//如果在椭圆内按下
      {
        _begin = e->pos();//记录拖拽开始的坐标位置
      }
    }
    else if (_drawType == 4)//直线
    {
      _lpress = true;//左键按下标志
      QRect rect;//鼠标按下，直线一端开始
      _line.append(rect);//将新直线添加到直线集合
      QRect& lastLine = _line.last();//拿到新直线
      lastLine.setTopLeft(e->pos());//记录鼠标的坐标(新直线开始一端坐标)
      _shape.append(4);
    }
  }
}


void MyPaint::mouseMoveEvent(QMouseEvent *e)
{
  if (_drag && ((_drawType == 2 && _rects.last().contains(e->pos()))
    || (_drawType == 3 && _ellipse.last().contains(e->pos()))))
  {
    setCursor(Qt::SizeAllCursor);//拖拽模式下，并且在拖拽图形中，将光标形状改为十字
  }
  else
  {
    setCursor(Qt::ArrowCursor);//恢复原始光标形状
    _drag = 0;
  }

  if (_lpress)
  {
    if (_drawType == 1)//铅笔画线
    {
      if (_lines.size() <= 0) return;//线条集合为空，不画线
      QVector<QPoint>& lastLine = _lines.last();//最后添加的线条，就是最新画的
      lastLine.append(e->pos());//记录鼠标的坐标(线条的轨迹)
      update();//触发窗体重绘
    }
    else if (_drawType == 2)
    {
      if (_drag == 0)//非拖拽
      {
        QRect& lastRect = _rects.last();//拿到新矩形
        lastRect.setBottomRight(e->pos());//更新矩形的右下角坐标
      }
      else//拖拽模式
      {
        QRect& lastRect = _rects.last();//拿到最后添加的矩形
        if (lastRect.contains(e->pos()))//在矩形的内部
        {
          int dx = e->pos().x() - _begin.x();//横向移动x
          int dy = e->pos().y() - _begin.y();//纵向移动y
          lastRect = lastRect.adjusted(dx, dy, dx, dy);//更新矩形的位置
          _begin = e->pos();//刷新拖拽点起始坐标
        }

      }
      update();//触发窗体重绘

    }
    else if (_drawType == 3)
    {
      if (_drag == 0)//非拖拽
      {
        QRect& lastEllipse = _ellipse.last();//拿到新椭圆
        lastEllipse.setBottomRight(e->pos());//更新椭圆的右下角坐标)

      }
      else//拖拽
      {
        QRect& lastEllipse = _ellipse.last();//拿到最后添加的矩形
        if (lastEllipse.contains(e->pos()))//在椭圆内部
        {
          int dx = e->pos().x() - _begin.x();//横向移动x
          int dy = e->pos().y() - _begin.y();//纵向移动y
          lastEllipse = lastEllipse.adjusted(dx, dy, dx, dy);
          _begin = e->pos();//刷新拖拽点起始坐标
        }

      }
      update();//触发窗体重绘
    }
    else if (_drawType == 4)
    {
      QRect& lastLine = _line.last();//拿到新直线
      lastLine.setBottomRight(e->pos());//更新直线另一端)
      update();//触发窗体重绘
    }
  }
}

void MyPaint::mouseReleaseEvent(QMouseEvent *e)
{
  if (_lpress)
  {
    qDebug() << "_drawType = %1 and release" << _drawType;
    if (_drawType == 1)
    {
      QVector<QPoint>& lastLine = _lines.last();//最后添加的线条，就是最新画的
      lastLine.append(e->pos());//记录线条的结束坐标
      _lpress = false;//标志左键释放

    }
    else if (_drawType == 2)
    {
      QRect& lastRect = _rects.last();//拿到新矩形
      if (!_drag)
      {
        lastRect.setBottomRight(e->pos());//不是拖拽时，更新矩形的右下角坐标)
        //刚画完矩形，将光标设置到新矩形的中心位置，并进入拖拽模式
        this->cursor().setPos(this->cursor().pos().x() - lastRect.width() / 2, this->cursor().pos().y() - lastRect.height() / 2);
        _drag = 1;

      }
      _lpress = false;

    }
    else if (_drawType == 3)
    {
      QRect& lastEllipse = _ellipse.last();//拿到新椭圆
      if (!_drag)
      {
        lastEllipse.setBottomRight(e->pos());//不是拖拽时，更新椭圆的右下角坐标)
        //刚画完椭圆，将光标设置到新椭圆的中心位置，并进入拖拽模式
        this->cursor().setPos(this->cursor().pos().x() - lastEllipse.width() / 2, this->cursor().pos().y() - lastEllipse.height() / 2);
        _drag = 1;

      }
      _lpress = false;
    }
    else if (_drawType == 4)//直线
    {
      //QRect& lastLine = _line.last();//拿到新矩形
      //lastLine.setBottomRight(e->pos());//更新矩形的右下角坐标)
      //_lpress = false;
    }
  }
}

void MyPaint::Lines()
{
  _drawType = 1;//铅笔
}

void MyPaint::Line()
{
  _drawType = 4;//直线
}

void MyPaint::Rects()
{
  _drawType = 2;//矩形

}

void MyPaint::Ellipses()
{
  _drawType = 3;//椭圆
}

void MyPaint::lineDone()
{
  int exp = 0;
  if (_drawType == 4 && _lpress)//直线
  {
    if (_shape.size() > 0)
    {
      if (_line.size() > 0)
      {
        _line.pop_back();
        _shape.pop_back();
        update();
      }
    }
  }
  if (exp)
  {
    exportData();
  }
  _lpress = false;//鼠标事件结束
  _drawType = 0;  //绘制事件结束
  qDebug() << "lineDone " << _drawType;
}

void MyPaint::SavePic()
{
  //弹出文件保存对话框
  QString fileName = QFileDialog::getSaveFileName(this, tr("保存"), "new.jpg", "Image (*.jpg *.png *.bmp)");

  if (fileName.length() > 0)
  {
    QPixmap pixmap(size());//新建窗体大小的pixmap
    QPainter painter(&pixmap);//将pixmap作为画布
    painter.fillRect(QRect(0, 0, size().width(), size().height()), Qt::white);//设置绘画区域、画布颜色
    this->render(&painter);//将窗体渲染到painter，再由painter画到画布
    pixmap.copy(QRect(0, 30, size().width(), size().height() - 30)).save(fileName);//不包含工具栏
  }
}

void MyPaint::OpenPic()
{
  //弹出文件打开对话框
  QString picPath = QFileDialog::getOpenFileName(this, tr("打开"), "", "Image Files(*.jpg *.png)");
  if (!picPath.isEmpty())//用户选择了文件
  {
    QPixmap pix;
    pix.load(picPath);//加载图片
    QPainter p(&_pixmap);
    p.drawPixmap(0, 30, pix);//添加工具栏的空间
    _openflag = 1;//设置文件打开标志
    update();//触发窗体重绘，将图片画到窗体
  }
}

void MyPaint::contextMenuEvent(QContextMenuEvent *)  //右键菜单事件
{
  _Rmenu->exec(cursor().pos());//在光标位置弹出菜单
}

void MyPaint::keyPressEvent(QKeyEvent *e) //按键事件
{
  //Ctrl+Z撤销
  if (e->key() == Qt::Key_Z && e->modifiers() == Qt::ControlModifier)
  {
    if (_shape.size() > 0)
    {
      switch (_shape.last())
      {
      case 1: _lines.pop_back();
        break;
      case 2: _rects.pop_back();
        break;
      case 3: _ellipse.pop_back();
        break;
      case 4: _line.pop_back();
        break;
      }
      _shape.pop_back();
      _drag = 0;//设置为非拖拽模式
      update();
    }
  }
  else if (e->key() == Qt::Key_S && e->modifiers() == Qt::ControlModifier)//保存
  {
    SavePic();//Ctrl+S保存
  }
}


int MyPaint::exportData(void)
{
  std::string path = "../.";
  FILE *fp;
  int i = 0;
  string filename = path + "/Paint Data" + ".ini";
  fopen_s(&fp, filename.c_str(), "w+");
  if (fp == NULL)
  {
    goto Error;
  }

  fprintf(fp, "[Shape]\n");
  fprintf(fp, "Size= %d\n", _shape.size());
  if (_shape.size())
  {
    fprintf(fp, "Data= %d", _shape.at(0));
    if (_shape.size() > 1)
    {
      for (int c = 1; c < _shape.size(); ++c)//控制用户当前所绘图形总数
      {
        fprintf(fp, ",%d", _shape.at(c));
      }
    }
    fprintf(fp, "\n");
  }
  fprintf(fp, "[Line]\n");
  fprintf(fp, "Size= %d\n", _line.size());
  if (_line.size())
  {
    fprintf(fp, "Data= %d,%d,%d,%d", _line.at(0).x(), _line.at(0).y(), _line.at(0).width(), _line.at(0).height());
    for (int c = 1; c < _line.size(); ++c)//控制用户当前所绘图形总数
    {
      fprintf(fp, " | %d,%d,%d,%d", _line.at(c).x(), _line.at(c).y(), _line.at(c).width(), _line.at(c).height());
    }
    fprintf(fp, "\n");
  }
  fprintf(fp, "[Rects]\n");
  fprintf(fp, "Size= %d\n", _rects.size());
  if (_rects.size())
  {
    fprintf(fp, "Data= %d,%d,%d,%d", _rects.at(0).x(), _rects.at(0).y(), _rects.at(0).width(), _rects.at(0).height());
    for (int c = 1; c < _rects.size(); ++c)//控制用户当前所绘图形总数
    {
      fprintf(fp, " | %d,%d,%d,%d", _rects.at(c).x(), _rects.at(c).y(), _rects.at(c).width(), _rects.at(c).height());
    }
    fprintf(fp, "\n");
  }
  fprintf(fp, "[Ellipse]\n");
  fprintf(fp, "Size= %d\n", _ellipse.size());
  if (_ellipse.size())
  {
    fprintf(fp, "Data= %d,%d,%d,%d", _ellipse.at(0).x(), _ellipse.at(0).y(), _ellipse.at(0).width(), _ellipse.at(0).height());
    for (int c = 1; c < _ellipse.size(); ++c)//控制用户当前所绘图形总数
    {
      fprintf(fp, " | %d,%d,%d,%d", _ellipse.at(c).x(), _ellipse.at(c).y(), _ellipse.at(c).width(), _ellipse.at(c).height());
    }
    fprintf(fp, "\n");
  }
  fclose(fp);
  return 1;

Error:
  return -1;
}

int MyPaint::importData(void)
{
  QRect rect;
  std::string path = "..//Paint Data.ini";
  IniFile ini;
  ini.load(path);
  int ret = 0;
  std::string datamsg;
  int size = 0;
  string section[3] = { "Line", "Rects", "Ellipse" };
  QVector<QRect> *apRec[3] = { &_line, &_rects, &_ellipse };

  size = ini.getIntValue("Shape", "Size", ret);
  if (ret == RET_ERR)
    goto Error;
  else
  {
    if (size == 0)
      goto Ret;
  }
  datamsg = ini.getStringValue("Shape", "Data", ret);
  if (ret == RET_ERR)
    goto Error;
  else
  {
    vector<string> data = split(datamsg, ",");
    if (data.size() != size)
      goto ErrorData;
    for (int i = 0; i < size; i++)
      _shape.append(atoi(data[i].c_str()));
  }

  

  for (int i = 0; i < 3; i++)
  {
    size = ini.getIntValue(section[i], "Size", ret);
    if (ret == RET_ERR)
      goto Error;
    datamsg = ini.getStringValue(section[i], "Data", ret);
    if (ret == RET_ERR)
      goto Error;

    if (getDataFromIni(size, datamsg, apRec[i]) < 0)
      goto Error;
  }

  return 1;
ErrorData:
  printf("Data error!\r\n");
Error:
  printf("importData error!\r\n");
  return -1;
Ret:
  return 1;
}


int MyPaint::getDataFromIni(int size, string datamsg, QVector<QRect> *vdata)
{
  QRect rect;
  int ret = 0;
  vector<string> data;

  data = split(datamsg, "|");
  if (data.size() != size)
    goto ErrorData;
  for (int i = 0; i < data.size(); i++){
    vector<string> data1 = split(data[i], ",");
    rect.setX(atoi(data1[0].c_str()));
    rect.setY(atoi(data1[1].c_str()));
    rect.setWidth(atoi(data1[2].c_str()));
    rect.setHeight(atoi(data1[3].c_str()));
    vdata->append(rect);
  }
  goto Ret;
ErrorData:
  printf("Data error!\r\n");
  return -2;
Error:
  printf("importData error!\r\n");
  return -1;
Ret:
  return 1;
}